import datetime
from app.functions import *
from app.config import SysConfig
import hashlib
import hmac
import time
from datetime import datetime, timezone
import json
from http.client import HTTPSConnection
import ssl


class TencentDNS:
    api_url = 'https://dnspod.tencentcloudapi.com'
    API_VERSION = "2021-03-23"

    def __init__(self, config):
        self.config = {
            'secretId': config.get('secretId', ''),
            'secretKey': config.get('secretKey', '')
        }

    def CreateRecord(self, domain, subDomain, recordType, value, params={}):
        action = "CreateRecord"
        data = {
            "Domain": domain,
            "RecordType": recordType,
            "RecordLine": "默认",
            "Value": value,
            "SubDomain": subDomain,
            "Status": params.get('Status', 'ENABLE'),
            "Remark": params.get('Remark', ''),
        }
        optionsFields = {"TTL": 600, "Weight": 20, "MX": 10, "RecordLineId": 0, "DomainId": 0}
        for key, default in optionsFields.items():
            if key in params:
                data[key] = params.get(key, default)
        headers = self.buildHeaderData('POST', action, data)
        return self.sendHttpRequest(headers.get('Host'), data, headers)

    def ModifyRecord(self, domain, recordId, subDomain, recordType, value, params={}):
        action = "ModifyRecord"
        data = {
            "Domain": domain,
            "RecordType": recordType,
            "RecordLine": "默认",
            "Value": value,
            "RecordId": recordId,
            "SubDomain": subDomain,
            "Status": params.get('Status', 'ENABLE'),
            "Remark": params.get('Remark', ''),
        }
        optionsFields = {"TTL": 600, "Weight": 20, "MX": 10, "RecordLineId": 0, "DomainId": 0}
        for key, default in optionsFields.items():
            if key in params:
                data[key] = params.get(key, default)
        headers = self.buildHeaderData('POST', action, data)
        return self.sendHttpRequest(headers.get('Host'), data, headers)

    def DeleteRecord(self, domain, recordId, domainId=0):
        action = "DeleteRecord"
        data = {
            "Domain": domain,
            "RecordId": recordId,
            "DomainId": domainId,
        }
        headers = self.buildHeaderData('POST', action, data)
        return self.sendHttpRequest(headers.get('Host'), data, headers)

    def DescribeRecordList(self, domain, params={}):
        action = "DescribeRecordList"
        data = {
            "Domain": domain,
            "Subdomain": params.get('subDomain', ''),
            "RecordType": params.get('recordType', ''),
        }
        headers = self.buildHeaderData('POST', action, data)
        return self.sendHttpRequest(headers.get('Host'), data, headers)

    def sendHttpRequest(self, url, params, header={}):
        headers = {
            "Content-Type": "application/json; charset=utf-8"
        }
        if header:
            headers.update(header)

        bodyStr = json.dumps(params, ensure_ascii=False)

        try:
            context = ssl._create_unverified_context()
            req = HTTPSConnection(url, context=context)
            req.request("POST", '/', headers=headers, body=bodyStr.encode("utf-8"))
            resp = req.getresponse()
            statusCode = resp.status
            if statusCode != 200:
                return funReturn(SysConfig.STATUS_CODE_DATAERROR, 'request failed')
            responseData = json.loads(resp.read().decode("utf-8"))
            errorData = responseData.get('Response', {}).get('Error', {})
            if errorData:
                msg = errorData.get('Message', '')
                code = errorData.get('Code', '')
                msg = f"{code}:{msg}" if code else msg
                if code == "ResourceNotFound.NoDataOfRecord":
                    return funReturn(SysConfig.STATUS_CODE_SUCCESS, 'success', {})
                return funReturn(SysConfig.STATUS_CODE_INSIDEERROR, msg)
            return funReturn(SysConfig.STATUS_CODE_SUCCESS, 'success', responseData.get('Response', {}))
        except Exception as err:
            return funReturn(SysConfig.STATUS_CODE_INSIDEERROR, str(err))

    def buildHeaderData(self, method, action, params):
        signRes = self.createSign(method, action, params)
        return {
            "Authorization": signRes.get('authorization'),
            "Content-Type": "application/json; charset=utf-8",
            "Host": signRes.get('host'),
            "X-TC-Timestamp": signRes.get('timestamp'),
            "X-TC-Version": self.API_VERSION,
            "X-TC-Action": action
        }

    def createSign(self, method, action, params):

        host = self.api_url.replace("https://", "").replace("http://", "")
        service = "dnspod"
        algorithm = "TC3-HMAC-SHA256"
        timestamp = int(time.time())
        date = datetime.fromtimestamp(timestamp, tz=timezone.utc).strftime('%Y-%m-%d')

        # ************* 步骤 1：构造 CanonicalRequest *************
        http_request_method = method.upper()
        canonical_uri = "/"
        canonical_querystring = ""
        content_type = "application/json; charset=utf-8"
        canonical_headers = (
            f"content-type:{content_type}\n"
            f"host:{host}\n"
            f"x-tc-action:{action.lower()}\n"
        )
        signed_headers = "content-type;host;x-tc-action"
        payload = json.dumps(params, ensure_ascii=False)
        # 对请求体进行 SHA256 哈希
        hashed_request_payload = hashlib.sha256(payload.encode('utf-8')).hexdigest()
        canonical_request = (http_request_method + "\n" +
                             canonical_uri + "\n" +
                             canonical_querystring + "\n" +
                             canonical_headers + "\n" +
                             signed_headers + "\n" +
                             hashed_request_payload)

        # ************* 步骤 2：拼接待签名字符串 *************
        credential_scope = date + "/" + service + "/" + "tc3_request"
        hashed_canonical_request = hashlib.sha256(canonical_request.encode('utf-8')).hexdigest()
        string_to_sign = (algorithm + "\n" +
                          str(timestamp) + "\n" +
                          credential_scope + "\n" +
                          hashed_canonical_request)

        # ************* 步骤 3：计算签名 *************
        secret_date = self.sign(("TC3" + self.config.get('secretKey')).encode("utf-8"), date)
        secret_service = self.sign(secret_date, service)
        secret_signing = self.sign(secret_service, "tc3_request")
        signature = hmac.new(secret_signing, string_to_sign.encode('utf-8'), hashlib.sha256).hexdigest()
        # ************* 步骤 4：拼接 Authorization *************
        authorization = (algorithm + " " +
                         "Credential=" + self.config.get('secretId') + "/" + credential_scope + ", " +
                         "SignedHeaders=" + signed_headers + ", " +
                         "Signature=" + signature)

        return {
            'authorization': authorization,
            'timestamp': timestamp,
            'host': host
        }

    @staticmethod
    def sign(key, msg):
        return hmac.new(key, msg.encode("utf-8"), hashlib.sha256).digest()
